import {
  Component,
  OnInit,
  ViewEncapsulation,
  ChangeDetectionStrategy,
  Input,
  ViewChild,
  Output,
  EventEmitter,
  ChangeDetectorRef,
  OnDestroy,
  AfterViewInit,
  ElementRef,
  ViewContainerRef,
  TemplateRef,
  NgZone,
  Renderer2,
  OnChanges,
  SimpleChanges,
} from '@angular/core';
import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { Subject, merge, fromEvent, of, Observable } from 'rxjs';
import { filter, takeUntil, delay, distinctUntilChanged, tap } from 'rxjs/operators';
import {
  forEach as _forEach,
  filter as _filter,
  cloneDeep as _cloneDeep,
  every as _every,
  map as _map,
} from 'lodash';
import { I18NService } from '../core/i18n/api';
import { OverlayService } from '../core/overlay/api';
import { LvFilterMode, LvPureSortDirection as PureSort, LvSortDirection as SortDirection } from '../core/types';
import { InputBoolean, InputNumber } from '../core/utils/convert';
import { TypeUtils } from '../core/utils/type';
import { SortHeaderComponent, SortConfig } from '../sort/api';
import { PopoverDirective } from '../popover/api';
import { DatatableService } from './datatable.service';
import { initCheckboxError } from './datatable-errors';
import { CheckTypeEnum, FilterItem, TableFilterConfig as FilterConfig } from './interface';

@Component({
  selector: 'th[lv-th],th[lvTh],th',
  exportAs: 'lvTh',
  templateUrl: './th.component.html',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    '[class.lv-table-th]': '_parentComponent',
    '[class.lv-table-th-left]': 'lvAlign === "left" || !lvAlign',
    '[class.lv-table-th-center]': 'lvAlign === "center"',
    '[class.lv-table-th-right]': 'lvAlign === "right"',
    '[class.lv-resizer]': '_parentComponent?.lvResize && isResizable',
    '[class.lv-table-sticky-left-cell]': 'lvLeft',
    '[class.lv-table-sticky-right-cell]': 'lvRight',
    '[class.lv-table-column-has-sorters]': 'lvShowSort',
    '[class.lv-table-column-has-selection]': 'lvShowCheckbox',
    '[class.lv-table-column-filters-trigger]': 'filtersTrigger',
    '[style.left]': 'lvLeft',
    '[style.right]': 'lvRight',
    '(click)': '_changeSort()',
  },
})
export class ThComponent implements OnInit, OnDestroy, AfterViewInit, OnChanges, OnInit {
  // 输入输出属性
  @Input() lvCellKey: string; // 列主键
  @Input() lvCheckboxTip = ''; // 复选框提示信息
  @Input() lvLeft: string | boolean; // 固定列相对于左对齐 NEED_DO :后续支持自动计算
  @Input() lvRight: string | boolean; // 固定列相对于右对齐 NEED_DO :后续支持自动计算,有滚动条计算偏差问题

  @Input() lvFilters: FilterItem[] = []; // 过滤的条件
  @Input() lvSortDirection: SortDirection; // 关联排序组件
  @Input() @InputBoolean() lvFilterSearch; // 过滤列表支持搜索过滤
  @Input() lvDefaultSort: PureSort = 'asc'; // 排序切换从什么序开始  默认先从升序开始
  @Input() lvFilterIcon = 'lv-icon-filter'; // 自定义过滤图标，适配lvp组件，基础组件不推荐使用

  @Input() @InputBoolean() lvFilterCheckAll; // 过滤是否支持全选，多选模式下有效
  @Input() @InputBoolean() lvDisabled = false; // 复选框是否可点
  // == sort header
  @Input() @InputBoolean() lvShowSort = false; // 是否展示排序按钮
  @Input() @InputBoolean() lvDisableSortClear; // 是否禁用清除排序
  // == tips header
  @Input() @InputBoolean() lvShowTips = false; // 是否展示提示按钮

  // 表头宽度是否可拖拽
  @Input() @InputBoolean() lvResizable = true;
  @Input() lvRowsData: Array<{ [key: string]: any }>; // 渲染页可点击行数据 默认为renderData
  // == filter header
  @Input() @InputBoolean() lvShowFilter = false; // 是否展示过滤按钮
  @Input() @InputBoolean() lvFilterAuto = false; // 是否支持自动过滤, 默认手动
  // == custom header
  @Input() @InputBoolean() lvShowCustom = false; // 是否展示自定义头
  @Input() @InputBoolean() lvFilterAsync = false; // 是否为异步数据，虚拟滚动时生效
  // == checkbox
  @Input() @InputBoolean() lvShowCheckbox = false; // 是否展示复选框
  @Input() @InputBoolean() lvFilterMultiple = true; // 过滤模式，单选多选，默认多选
  @ViewChild('popover') _popover: PopoverDirective;
  @Input() @InputBoolean() lvCustomAllCheck = false;
  @Input() lvFilterMode: LvFilterMode = 'startsWith'; // 过滤模式，默认起始
  @Input() @InputNumber() lvFilterVirtualItemSize = 32; // 每行高度

  @Input() @InputBoolean() lvFilterSearchAsync = false; // 是否为异步过滤，虚拟滚动时生效
  @Output() lvFilterScrollEnd = new EventEmitter<any>(); // 虚拟滚动到底部时回调事件，虚拟滚动时生效
  @Input() lvAlign: 'left' | 'right' | 'center' = 'left'; // 标题对齐方式
  @Input() @InputBoolean() lvFilterCaseSensitive = false; // 过滤是否关心大小写，默认不关心
  // 虚拟滚动
  @Input() @InputBoolean() lvFilterVirtualScroll = false; // 是否使用虚拟滚动（大数据场景使用）
  @Input() @InputNumber() lvFilterVirtualMaxBuffer = 200; // 渲染新项时最大缓冲高度
  @Input() @InputNumber() lvFilterVirtualMinBuffer = 100; // 视图之外渲染的最小缓冲区数，若缓存区数量低于此数量将渲染新项
  @Output() lvFilterSearchChange = new EventEmitter<any>(); // 搜索变化时回调事件，虚拟滚动时生效
  @Input() lvFilterTemplate: TemplateRef<{ $implicit: any }>; // 自定义过滤模板

  @Output() lvFilterScrollingChange = new EventEmitter<any>(); // 虚拟滚动中回调事件，虚拟滚动时生效

  @Output() lvFilterChange = new EventEmitter<FilterConfig>(); // 触发filter变化回调函数

  @Output() lvFiltersChange = new EventEmitter<FilterItem[]>(); // filter列表变化回调

  @Output() lvFilterBeforeOpen = new EventEmitter<FilterItem[]>(); // filter列表变化回调
  @ViewChild(SortHeaderComponent) sortHeader: SortHeaderComponent;
  @ViewChild('filterSelectTpl') _filterSelectTpl: TemplateRef<any>;
  @Output() lvCheckChange = new EventEmitter<Array<{ [key: string]: any }>>(); // 返回选中项

  @ViewChild('resizeLine', { read: ElementRef }) _resizeLine: ElementRef;
  @Input() lvCustomSort: <T>(data: T[] | null, sort: SortConfig) => T[] | null; // 自定义排序
  @ViewChild('filter', { read: ElementRef }) _overlayFilterBtn: ElementRef<any>;
  @Input() lvCustomItemFilter: <T>(data: T | null, filter: FilterConfig) => boolean; // 自定义单项数据过滤
  @Input() lvCustomFilter: <T>(data: T[] | null, filter: FilterConfig) => T[] | null; // 自定义全部数据过滤
  // 外部可访问变量
  overlayRef;
  extraChecks = [];
  // 内部变量
  _parentComponent; // 父组件引用
  isResizable = true;
  virtualSelectedValue;

  filterSearchKey: string;
  checkType = CheckTypeEnum;
  filterOpen: boolean = false;
  activeFilter: boolean = false;
  filtersTrigger: boolean = false; // 标识是否filters高亮，用于判刑当前是否触发排序icon高亮
  resizeOffset = new Subject<{
    width?: number;
    initWidth?: number;
    offset?: number;
    totalOffset?: number;
    type?: 'mousedown' | 'mousemove' | 'mouseup';
  }>();

  private _activeElement: any;

  private _filterMap: any = {}; // 记录filter选中状态
  private _cacheFilters: FilterItem[];

  private _init$ = new Subject<number>();

  private _data: Array<{ [key: string]: any }>;

  private _destroy$ = new Subject<void>();

  private _rowsDataChanged: boolean = false; // 判断是否lvRowsData设置的标记

  private _rowsData: Array<{ [key: string]: any }>; // 全选比较的源数据(默认当前渲染)

  constructor(
    public elementRef: ElementRef,
    public i18n: I18NService,
    private _cdr: ChangeDetectorRef,
    private service: DatatableService,
    private viewContainerRef: ViewContainerRef,
    private overlayService: OverlayService,
    private overlay: Overlay,
    private ngZone: NgZone,
    private renderer: Renderer2,
  ) {
    this._activeElement = elementRef.nativeElement;
  }

  get _selection(): any {
    return this._parentComponent?.getSelection();
  }

  get multiple(): boolean {
    return !!this._parentComponent?.selectionMultiMode;
  }

  get _renderSelection(): any {
    return this._parentComponent?.getRenderSelection();
  }

  get isFullHalfCheck(): boolean {
    if (!this._parentComponent) {
      return false;
    }
    return !this.isFullCheck && !!this._selection.length;
  }

  get filterHalf(): boolean {
    const selectedLength = _filter(this.lvFilters, 'selected').length;
    return !this.filterCheckAll && !!selectedLength;
  }

  get isHalfCheck(): boolean {
    if (!this._parentComponent) {
      return false;
    }
    return !this.isAllCheck && !!this._renderSelection.length;
  }

  get isFullCheck(): boolean {
    if (!this._parentComponent) {
      return false;
    }

    const selectedLength = this._selection.length;
    const allLength = (this._data || []).length;

    return selectedLength > 0 && selectedLength === allLength;
  }

  get isAllCheck(): boolean {
    if (!this._parentComponent) {
      return false;
    }
    const selectedLength = this._renderSelection.length;
    const allLength = (this._rowsData || []).length;

    return selectedLength > 0 && selectedLength === allLength;
  }

  /**
   * 全选
   * 不为disable的项全部选中
   * disabled可不被选中
   * 不能全部为disabled
   */
  get filterCheckAll(): boolean {
    const data = this.lvFilters;
    if (!data || !data.length) {
      return false;
    }
    const disItems = _every(data, 'disabled');
    if (disItems) {
      return false;
    }

    const items = _filter(data, (item): any => item.disabled || item.selected);

    return items.length === data.length;
  }

  popoverBeforeOpen = (): void => {
    this.lvFilters = _cloneDeep(this._cacheFilters);
    this._filterMap = this._getFilterMap(this.lvFilters);
    this.filterSearchKey = '';
    this.lvFilterBeforeOpen.emit(this._cacheFilters);
    if (!this.lvFilterVirtualScroll) {
      return;
    }
    if (this.lvFilterMultiple) {
      this.virtualSelectedValue = [];
      this.lvFilters.forEach((item): void => {
        if (item.selected) {
          this.virtualSelectedValue.push(item);
        }
      });
    } else {
      this.virtualSelectedValue = this.lvFilters.find((item): boolean => item.selected);
    }
  };

  filterScrollEnd(event): void {
    this.lvFilterScrollEnd.emit(event);
  }

  filterSearchChange(event): void {
    this.lvFilterSearchChange.emit(event);
  }

  getResizeOffset(): Observable<any> {
    return this.resizeOffset.asObservable();
  }

  filterScrollingChange(event): void {
    this.lvFilterScrollingChange.emit(event);
  }

  // 点击过滤icon，阻止触发排序逻辑
  filterClick(event): void {
    event.stopPropagation();
    event.preventDefault();
  }

  getActiveFilterItem(filters: FilterItem[]): any {
    return _filter(filters, 'selected');
  }

  clearOverlayRef(): void {
    // 关闭下拉
    if (this._existOverlayRef()) {
      this.overlayRef.close();
    }
  }

  _existOverlayRef(): any {
    let res;
    if (this.overlayRef) {
      res = this.overlayRef.overlayRef.hasAttached();
    } else {
      res = this.overlayRef;
    }
    return res;
  }

  // 排序
  _changeSort(): void {
    if (!this.lvShowSort) {
      return;
    }

    this.sortHeader._changeSort();
  }

  updateActiveFilter(filters?: FilterItem[]): void {
    this.activeFilter = !!filters?.length;
  }

  ngOnDestroy(): void {
    this._destroy$.next();
    this._destroy$.complete();
    this.clearOverlayRef();
  }

  getSelectableData(data: Array<any>, exponent: string = 'disabled'): any {
    return _filter(data, (item): boolean => !item[exponent]);
  }

  _getFilterMap(source: Array<FilterItem>): any {
    const map = {};
    _forEach(source, (item): void => {
      map[item.key] = item;
    });
    return map;
  }

  ngOnInit(): void {
    // 单选模式不能设置checkbox
    this._parentComponent = this.service.getParentComponent();

    // 监听renderData变化来赋值rowsData
    if (this._parentComponent) {
      this._subscribeRenderData();
    }

    this.initExtraChecks();
  }

  _subscribeInitError(): void {
    if (!this._parentComponent) {
      return;
    }

    if (this.lvShowCheckbox && !this.multiple) {
      throw initCheckboxError('th', 'lvShowCheckbox');
    }

    // 待解决：多选模式必须设置lvRowsData  改为默认模式
  }

  // 重置过滤
  _resetFilter(): void {
    _forEach(this._filterMap, (item): void => {
      if (item.disabled) {
        return;
      }
      item.selected = false;
    });
    this.virtualSelectedValue = null;
    this._submitFilter(true);
    this._cdr.markForCheck();
  }

  // filter
  _selectedChange(value): void {
    this.lvFilterChange.emit({
      key: this.lvCellKey,
      value,
      customFilter: this.lvCustomFilter,
      customItemFilter: this.lvCustomItemFilter,
      filterMode: this.lvFilterMode,
      caseSensitive: !!this.lvFilterCaseSensitive,
    });
  }

  checkAllChange(): void {
    const all = this.filterCheckAll;
    _forEach(this.lvFilters, (item): void => {
      if (item.disabled) {
        return;
      }
      item.selected = !all;
      this._filterMap[item.key].selected = !all;
    });

    if (this.lvFilterAuto) {
      this._submitFilter();
    }
  }

  virtualToggleFilter(event): void {
    this.virtualSelectedValue = event;
    if (this.lvFilterMultiple) {
      this.virtualSelectedValue.forEach((item): void => {
        this._filterMap[item.key].selected = true;
      });
      if (this.lvFilterAuto) {
        this._submitFilter();
      }
    } else {
      this.toggleFilter(this.virtualSelectedValue);
    }
  }

  initExtraChecks(): void {
    this.extraChecks = [
      {
        key: this.checkType.SINGLE,
        label: this.i18n.get('thisPage'),
        onSelect: (e): void => this._toggleSelection(e),
      },
      {
        key: this.checkType.All,
        label: this.i18n.get('allPage'),
        onSelect: (e): void => this._toggleSelection(e, this._data, this.checkType.All),
      },
    ];
  }

  filterSearch(value: string): void {
    const targetValue = value.toString().trim();

    let filters: FilterItem[] = _cloneDeep(this._cacheFilters);
    // selected
    filters = _map(filters, (item): any => {
      item.selected = this._filterMap[item.key].selected;
      return item;
    });
    this.lvFilters = _filter(filters, (item): boolean => item.label.toLowerCase().includes(targetValue.toLowerCase()));
  }

  ngAfterViewInit(): void {
    this._subscribeInitError();
    this._renderView();
    this._init$.next(0);
    this._init$.complete();
    // 在table-data-source做了防抖处理导致需要下个生命周期执行
    setTimeout((): void => {
      this.resizeColWidth();
    }, 0);

    // 监听当前filterPanel打开状态，控制filter图标高亮
    this._popover?.popover?.openState$.pipe(takeUntil(this._popover?.destroy$)).subscribe((open): void => {
      this.filterOpen = open;
    });
  }

  toggleFilter(source: FilterItem): void {
    if (source.disabled) {
      return;
    }
    if (!this.lvFilterMultiple) {
      const map = this._getFilterMap(this.lvFilters);
      _forEach(this._filterMap, (item): void => {
        if (item.disabled) {
          return;
        }
        item.selected = false;
        map[item.key] && (map[item.key].selected = false);
      });
    }
    source.selected = !source.selected;
    this._filterMap[source.key].selected = source.selected;

    if (this.lvFilterAuto) {
      this._submitFilter();
    }
  }

  // 复选框
  _toggleSelection(e: MouseEvent, data = this._rowsData, type = this.checkType.SINGLE): void {
    e.stopPropagation();
    if (this.lvDisabled) {
      return;
    }
    this.getAllCheckByType(type)
      ? this._parentComponent.deleteSelection(data)
      : this._parentComponent.bulkSelection(data);
    this.service.setCheckboxStream({
      key: 'th',
      check: this.getAllCheckByType(type),
      halfCheck: type === this.checkType.SINGLE ? this.isHalfCheck : this.isFullHalfCheck,
    });
    const selection = type === this.checkType.SINGLE ? this._renderSelection : this._selection;

    this.lvCheckChange.emit(selection);
  }

  /**
   * 监听父组件的renderData变换（多选情况下在没设置lvRowsData前提下
   * renderData --update--> rowsData 为了更新全选比较源数据
   */
  _subscribeRenderData(): void {
    this._parentComponent.renderDataChange$
      .pipe(
        tap((): void => {
          // 多选且自动过滤不关闭面板时，面板位置需根据targe元素的位置变更。
          // 表格数据变更视图更新后，targe元素的位置才会发生变更
          if (this.lvFilterMultiple && this.lvFilterAuto && this._popover) {
            this._popover.updatePosition();
          }
        }),
        filter((): boolean => this.lvShowCheckbox && !this._rowsDataChanged),
        takeUntil(this._destroy$),
      )
      .subscribe((): void => {
        this._rowsData = this._parentComponent.getUnfoldRenderData();
        this._data = this.getSelectableData(this._parentComponent?.lvData);
      });
  }

  /**
   * td checkbox流变更 和table render 流变更 和 table selection流变更 更新th checkbox状态
   */
  _renderView(): void {
    // 只有checkbox的th才监听
    if (!(this.lvShowCheckbox && this.multiple)) {
      return;
    }
    const tableStream = this._parentComponent
      ? // tslint:disable-next-line
        merge(
          this._parentComponent.renderDataChange$.pipe(delay(0)),
          this._parentComponent.selectionChange$,
          this._parentComponent.lvSelectionChange,
        )
      : of(null);
    const checkboxStream = merge(
      this._init$, // 初始化
      this.service.getCheckboxStream().pipe(filter((res): boolean => (res as any).key === 'td')),
    );

    merge(tableStream, checkboxStream)
      .pipe(delay(0), takeUntil(this._destroy$))
      .subscribe((): void => this._cdr.markForCheck());
  }

  // 确认过滤
  _submitFilter(reset = false): void {
    // 自动过滤时，不应清除过滤项的搜索条件
    if (this.lvFilterAuto) {
      this.filterSearch(this.filterSearchKey);
    } else {
      this.filterSearch('');
    }

    _forEach(this._cacheFilters, (item): void => {
      this._filterMap[item.key] && (item.selected = this._filterMap[item.key].selected);
    });

    const filters = _filter(this._cacheFilters, 'selected');
    const filterValues = _map(filters, 'value');

    this.lvFiltersChange.emit(this._cacheFilters);
    this.updateActiveFilter(this.getActiveFilterItem(this.lvFilters));

    this.lvFilterChange.emit({
      key: this.lvCellKey,
      value: filterValues,
      customFilter: this.lvCustomFilter,
      filterMode: 'in',
      caseSensitive: !!this.lvFilterCaseSensitive,
    });

    // 多选且自动过滤时，勾选过滤条件后不关闭过滤面板，reset均需关闭过滤面板
    if (!(this.lvFilterMultiple && this.lvFilterAuto) || reset) {
      this._popover?.hide();
    }
  }

  // select filter
  _toggleFilterSelect(): void {
    if (!this._existOverlayRef()) {
      const config = new OverlayConfig({
        hasBackdrop: false,
        scrollStrategy: this.overlay.scrollStrategies.block(),
        positionStrategy: this.overlay
          .position()
          .flexibleConnectedTo(this._overlayFilterBtn)
          .withPositions([
            {
              originX: 'start',
              originY: 'bottom',
              overlayX: 'start',
              overlayY: 'top',
            },
            {
              originX: 'start',
              originY: 'top',
              overlayX: 'start',
              overlayY: 'bottom',
            },
          ]),
      });
      const extendConfig = {
        backdropBindClose: true,
      };

      // 处理没点按钮 下拉消失选中状态不对应问题
      this._cacheFilters = _cloneDeep(this.lvFilters || []);
      const portal = new TemplatePortal(this._filterSelectTpl, this.viewContainerRef, {
        $implicit: this._cacheFilters,
      });
      this.overlayRef = this.overlayService.open(portal, config, extendConfig);
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    // 初始化过滤列表
    const { lvFilters, lvRowsData: rowsDataChange, lvFilterMultiple, lvFilterAuto, lvResizable } = changes;
    if (lvFilters) {
      const filters = lvFilters.currentValue;
      this._cacheFilters = _cloneDeep(filters);
      this._filterMap = this._getFilterMap(filters);
      this.updateActiveFilter(this.getActiveFilterItem(filters));

      if (this.filterSearchKey) {
        this.filterSearch(this.filterSearchKey);
      }
    }

    // 初始化rowsData
    if (rowsDataChange) {
      this._rowsDataChanged = true; // 标识是否已经被改变
      this._rowsData = rowsDataChange.currentValue;
      this._data = this.getSelectableData(this._parentComponent?.lvData);
    }

    if (lvFilterMultiple) {
      if (lvFilterMultiple.currentValue) {
        this.lvFilterAuto = false;

        if (lvFilterAuto?.currentValue) {
          this.lvFilterAuto = true;
        }
      } else {
        this.lvFilterAuto = true;

        if (lvFilterAuto && !lvFilterAuto.currentValue) {
          this.lvFilterAuto = false;
        }
      }
    }

    if (lvResizable) {
      this.isResizable = TypeUtils.isUndefined(lvResizable.currentValue) ? true : this.lvResizable;
    }
  }

  fromEventMousedown(params: any): void {
    fromEvent(params.downActiveElement, 'mousedown')
      .pipe(takeUntil(this._destroy$))
      .subscribe((): void => {
        this.renderer.setStyle(this.elementRef.nativeElement, 'pointer-events', 'none');
        params.isDragStart = true;
        // 记录
        params.currentWidth = this._activeElement.getBoundingClientRect().width;
        params.startX = this.elementRef.nativeElement.getBoundingClientRect().right;
        params.lastClientX = params.startX;
        // 给页面设置不可选样式，避免导致不触发mouseup
        this.toggleTextSelection(params.bodyElement, true);
        this.showResizeHelpLine(params.resizeHelpLine);
        this.resizeOffset.next({ initWidth: params.currentWidth, type: 'mousedown' });
      });
  }

  fromEventMousemove(params: any): void {
    fromEvent(params.bodyElement, 'mousemove')
      .pipe(
        filter((): boolean => params.isDragStart),
        distinctUntilChanged(),
        takeUntil(this._destroy$),
      )
      .subscribe((res: any): void => {
        if (!params.isDragStart) {
          return;
        }

        params.endX = res.clientX;
        params.offsetX = params.endX - params.lastClientX;
        params.totalOffsetX = params.endX - params.startX;
        params.lastClientX = params.endX;

        if (params.offsetX === 0 || params.currentWidth + params.totalOffsetX < params.minWidth) {
          return;
        }

        // 辅助线的位置为完成move之后的x的位置减去表格在页面中的left值
        this.resizeOffset.next({
          width: params.currentWidth + params.totalOffsetX,
          offset: params.offsetX,
          totalOffset: params.totalOffsetX,
          type: 'mousemove',
        });
      });
  }

  fromEventMouseup(params: any): void {
    fromEvent(params.bodyElement, 'mouseup')
      .pipe(
        filter((): boolean => params.isDragStart),
        takeUntil(this._destroy$),
      )
      .subscribe((res: MouseEvent): void => {
        params.isDragStart = false;
        params.endX = res.clientX;
        params.offsetX = params.endX - params.lastClientX;
        params.totalOffsetX = params.endX - params.startX;

        // mouseup时，无论拖拽后宽度是否变更，都已完成拖拽操作，样式都需要变更
        this.toggleTextSelection(params.bodyElement, false); // 恢复页面可选样式
        this.hideResizeHelpLine(params.resizeHelpLine);
        this.renderer.removeStyle(this.elementRef.nativeElement, 'pointer-events');
        if (params.offsetX === 0 || params.currentWidth + params.totalOffsetX < params.minWidth) {
          return;
        }

        this.resizeOffset.next({
          width: params.currentWidth + params.offsetX,
          offset: params.offsetX,
          totalOffset: params.totalOffsetX,
          type: 'mouseup',
        });
      });
  }

  /**
   * 调整表头宽度,改变当前列宽和相邻列宽
   * NEED_DO: 不支持分组情况
   * 1. mousedown: 记录当前列、相邻列宽
   * 2. mousemove: 更新辅助线位置
   * 3. mouseup: 清除,更新当前列宽
   */
  resizeColWidth(): void {
    const notResizable = !this._parentComponent || !this._parentComponent.lvResize || !this.isResizable;
    const isFixedColumn = this.lvLeft || this.lvRight; // 固定列不可被拖拽
    if (notResizable || isFixedColumn) {
      return;
    }

    this.ngZone.runOutsideAngular((): void => {
      const resizeLineRef = this._resizeLine;
      if (!resizeLineRef) {
        return;
      }

      const params = {
        isDragStart: false,
        currentWidth: undefined, // 当前col宽度
        startX: undefined,
        endX: undefined,
        lastClientX: 0, // 上一次完成移动后的鼠标所在位置X值
        offsetX: undefined, // 每次 move 距离
        totalOffsetX: undefined, // 整体 move 距离
        downActiveElement: this._activeElement.querySelector('.lv-table-th-deliver'),
        bodyElement: document.body,
        resizeHelpLine: resizeLineRef.nativeElement,
        minWidth: this._parentComponent.lvResizeMinWidth,
      };

      // 1
      this.fromEventMousedown(params);
      // 2
      this.fromEventMousemove(params);
      // 3
      this.fromEventMouseup(params);
    });
  }

  private getAllCheckByType(type: CheckTypeEnum): boolean {
    return type === this.checkType.SINGLE ? this.isAllCheck : this.isFullCheck;
  }

  /**
   * 当光标移到感应区时，出现拖动辅助线
   * 辅助线的位置为当前开始位置减去表格在页面中的left值
   */
  private showResizeHelpLine(resizeHelpLine): void {
    this.renderer.addClass(this._activeElement, 'lv-table-column-resizing');
    this.renderer.removeClass(resizeHelpLine, 'lv-display-none');
  }

  /**
   * 当光标离开感应区时，拖动辅助线消失
   */
  private hideResizeHelpLine(resizeHelpLine): void {
    this.renderer.addClass(resizeHelpLine, 'lv-display-none');
    this.renderer.removeClass(this._activeElement, 'lv-table-column-resizing');
  }

  /**
   * 当列拖动进行时阻止文本选中
   */
  private toggleTextSelection(body, toggle: boolean): void {
    if (toggle) {
      this.renderer.addClass(body, 'lv-user-select-disabled');
      this.renderer.setAttribute(body, 'unselectable', 'on');
    } else {
      this.renderer.removeClass(body, 'lv-user-select-disabled');
      this.renderer.removeAttribute(body, 'unselectable');
    }
  }
}
